﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Soft
{
    /// <summary>
    /// 测试类
    /// </summary>
    public abstract class TestObject : SimpleOutputScreenObject, ITestRun
    {
        
        public TestObject()
        {
            this.Waiting = 0;
            this.ProgressBarColor = TestObject.ShowColor.Progress;
            this.ShowInformation(string.Format("Initialization program.({0})", base.GetType().Name));
        }


        public TestObject(int waitingSecond) : this()
        {
            this.Waiting = waitingSecond;
        }


        /// <summary>
        /// run() 具体的执行方法
        /// </summary>
        public void Run()
        {
            this.ShowInformation("Start test program.");
            this.ShowLine(80, true, ConsoleColor.Green);
            this.mStopwatch.Reset();
            this.mStopwatch.Start();
            //调用重载的testProgram方法
            this.TestProgram();
            this.mStopwatch.Stop();
            this.ShowInformation("");
            this.ShowLine(80, true, ConsoleColor.Green);
            this.ShowInformation(string.Format("The test program is over. {0} milliseconds used.", this.mStopwatch.ElapsedMilliseconds));
            this.SetColor(new TestObject.ShowColor
            {
                Background = ConsoleColor.Black,
                Foreground = ConsoleColor.Green
            });
            if (this.Waiting == 0)
            {
                this.ShowInformation("Please press any key to return.");
                Console.ReadKey();
                return;
            }
            if (this.Waiting > 0)
            {
                int handle = this.StartProgressBar("Waiting seconds:", true);
                for (int i = this.Waiting; i > 0; i--)
                {
                    this.SetProgressBar(handle, (double)i);
                    Thread.Sleep(1000);
                }
            }
        }

      
        /// <summary>
        /// 线程睡眠的时间
        /// </summary>
        public int Waiting { get; protected set; }


        /// <summary>
        /// testProgram()的抽象方法
        /// </summary>
        protected abstract void TestProgram();


        /// <summary>
        /// 设置显示行的样式
        /// </summary>
        /// <param name="length"></param>
        /// <param name="doubleLine"></param>
        /// <param name="color"></param>
        public void ShowLine(int length = 80, bool doubleLine = false, ConsoleColor color = ConsoleColor.White)
        {
            char paddingChar = doubleLine ? '=' : '-';
            ConsoleColor foregroundColor = Console.ForegroundColor;
            Console.ForegroundColor = color;
            Console.WriteLine("".PadLeft(length, paddingChar));
            Console.ForegroundColor = foregroundColor;
        }


        /// <summary>
        /// 设置显示的样式
        /// </summary>
        /// <param name="doubleLine"></param>
        /// <param name="color"></param>
        public void ShowLine(bool doubleLine, ConsoleColor color = ConsoleColor.White)
        {
            this.ShowLine(80, doubleLine, color);
        }


        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="text"></param>
        public void ShowInformation(string text)
        {
            Console.WriteLine(text);
        }


        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="format"></param>
        /// <param name="args"></param>
        public void ShowInformation(string format, params object[] args)
        {
            Console.WriteLine(string.Format(format, args));
        }


        /// <summary>
        /// 显示结果信息
        /// </summary>
        /// <param name="result">要显示的结果</param>
        public void ShowInformation(IResult result)
        {
            this.ShowInformation(result.Error.Text);
        }


        /// <summary>
        /// 显示错误
        /// </summary>
        /// <param name="e"></param>
        public void ShowError(IError e)
        {
            this.ShowError(e.Error.Text);
        }


        /// <summary>
        /// 显示异常
        /// </summary>
        /// <param name="e"></param>
        public void ShowError(Exception e)
        {
            StringBuilder stringBuilder = new StringBuilder();
            do
            {
                stringBuilder.AppendLine(e.ToString());
                e = e.InnerException;
            }
            while (e != null);
        }


        /// <summary>
        /// 显示错误
        /// </summary>
        /// <param name="text">异常信息  文本</param>
        public void ShowError(string text)
        {
            TestObject.ShowColor currentClolor = TestObject.ShowColor.CurrentClolor;
            this.SetColor(TestObject.ShowColor.Error);
            Console.WriteLine("[" + DateTime.Now.ToDateTimeString(false) + "]" + text);
            this.SetColor(currentClolor);
        }


        /// <summary>
        /// 进度条颜色
        /// </summary>
        public TestObject.ShowColor ProgressBarColor { get; set; }


        /// <summary>
        /// 设置进度条的提示
        /// </summary>
        /// <param name="prompt"></param>
        /// <param name="newLine"></param>
        /// <returns></returns>
        public int StartProgressBar(string prompt, bool newLine = false)
        {
            object obj = this.mThreadTag;
            int result;
            lock (obj)
            {
                TestObject.ShowColor currentClolor = TestObject.ShowColor.CurrentClolor;
                this.mProgressBarPrompt = ((prompt.Length > 70) ? prompt.Substring(0, 70) : prompt);
                this.SetColor(this.ProgressBarColor);
                if (newLine)
                {
                    Console.WriteLine();
                }
                Console.Write(prompt);
                int num;
                if (this.mProgressBarItems.Count <= 0)
                {
                    num = 0;
                }
                else
                {
                    num = this.mProgressBarItems.Max((TestObject.ProgressBarItem e) => e.Handle) + 1;
                }
                int num2 = num;
                this.mProgressBarItems.Add(new TestObject.ProgressBarItem
                {
                    Handle = num2,
                    Position = new TestObject.ScreenPosition
                    {
                        Left = Console.CursorLeft,
                        Top = Console.CursorTop
                    }
                });
                this.SetColor(currentClolor);
                result = num2;
            }
            return result;
        }


        /// <summary>
        /// 设置进度条提示文本
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="index"></param>
        /// <param name="count"></param>
        public void SetProgressBar(int handle, double index, double count)
        {
            double num = 0.0;
            if (count != 0.0)
            {
                num = index / count;
            }
            this.SetProgressBar(handle, string.Format("{0:##0.0%}", num));
        }


        /// <summary>
        /// 设置进度条的索引
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="value"></param>
        public void SetProgressBar(int handle, double value)
        {
            string text = string.Format("{0:##0.#}", value);
            this.SetProgressBar(handle, text.PadRight(10 - text.Length));
        }


        /// <summary>
        /// 设置进度条的宽度
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="index"></param>
        /// <param name="count"></param>
        /// <param name="width"></param>
        public void SetProgressBar(int handle, double index, double count, int width)
        {
            if (width < 3)
            {
                width = 3;
            }
        }


        /// <summary>
        /// 设置颜色
        /// </summary>
        /// <param name="color"></param>
        public void SetColor(TestObject.ShowColor color)
        {
            Console.BackgroundColor = color.Background;
            Console.ForegroundColor = color.Foreground;
        }

       
        /// <summary>
        /// 设置控制台的光标是否可见
        /// </summary>
        public bool CursorVisible
        {
            get
            {
                return Console.CursorVisible;
            }
            set
            {
                Console.CursorVisible = value;
            }
        }


        /// <summary>
        /// 设置进度条
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="text"></param>
        private void SetProgressBar(int handle, string text)
        {
            object obj = this.mThreadTag;
            lock (obj)
            {
                int num = this.mProgressBarItems.FindIndex((TestObject.ProgressBarItem e) => e.Handle == handle);
                if (num < 0)
                {
                    throw new KeyNotFoundException("The handle not found.");
                }
                TestObject.ProgressBarItem progressBarItem = this.mProgressBarItems[num];
                TestObject.ShowColor currentClolor = TestObject.ShowColor.CurrentClolor;
                TestObject.ScreenPosition screenPosition = new TestObject.ScreenPosition
                {
                    Left = Console.CursorLeft,
                    Top = Console.CursorTop
                };
                try
                {
                    Console.SetCursorPosition(progressBarItem.Position.Left, progressBarItem.Position.Top);
                    this.SetColor(this.ProgressBarColor);
                    Console.Write(text);
                }
                catch (Exception ex)
                {
                    Console.WriteLine();
                    Console.WriteLine("System error:" + ex.Message);
                }
                finally
                {
                    this.SetColor(currentClolor);
                    Console.SetCursorPosition(screenPosition.Left, screenPosition.Top);
                }
            }
        }


        /// <summary>
        /// 进度条提示
        /// </summary>
        private string mProgressBarPrompt = "";


        /// <summary>
        /// 进度条集合
        /// </summary>
        private List<TestObject.ProgressBarItem> mProgressBarItems = new List<TestObject.ProgressBarItem>();


        /// <summary>
        /// 计时器
        /// </summary>
        private Stopwatch mStopwatch = new Stopwatch();


        /// <summary>
        /// 同步锁
        /// </summary>
        private object mThreadTag = new object();


        /// <summary>
        ///屏幕的位置 
        /// </summary>
        private struct ScreenPosition
        {
            public int Left;

            public int Top;
        }


        /// <summary>
        /// 进度条
        /// </summary>
        private struct ProgressBarItem
        {

            /// <summary>
            /// 进度条的索引（第几个进度条）
            /// </summary>
            public int Handle;


           /// <summary>
           /// 在屏幕的位置
           /// </summary>
            public TestObject.ScreenPosition Position;
        }


        /// <summary>
        /// 显示颜色
        /// </summary>
        public class ShowColor
        {
     
            /// <summary>
            /// 设置前景色
            /// </summary>
            public ConsoleColor Foreground { get; set; }

      
            /// <summary>
            /// 设置背景色
            /// </summary>
            public ConsoleColor Background { get; set; }


            /// <summary>
            /// 获取控制台 当前的颜色
            /// </summary>
            public static TestObject.ShowColor CurrentClolor
            {
                get
                {
                    return new TestObject.ShowColor
                    {
                        Background = Console.BackgroundColor,
                        Foreground = Console.ForegroundColor
                    };
                }
            }


            /// <summary>
            /// 进度条的颜色 
            /// </summary>
            public static TestObject.ShowColor Progress = new TestObject.ShowColor
            {
                Background = ConsoleColor.Black,
                Foreground = ConsoleColor.Blue
            };


            /// <summary>
            /// 错误的颜色
            /// </summary>
            public static TestObject.ShowColor Error = new TestObject.ShowColor
            {
                Background = ConsoleColor.Black,
                Foreground = ConsoleColor.Red
            };

       
            /// <summary>
            /// 警告的颜色
            /// </summary>
            public static TestObject.ShowColor Warning = new TestObject.ShowColor
            {
                Background = ConsoleColor.Black,
                Foreground = ConsoleColor.Yellow
            };


        }


    }
}
